﻿using SanlieHash.SecureHash;
using System;
using System.Collections.Generic;
using System.Text;

namespace mssql_password
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var needExit = false;
            var m = string.Empty;
            do {
                Console.Write("> ");

                var cmd = Console.ReadLine();
                switch (cmd.ToLower())
                {
                    case "exit":
                    case "quit":
                    case "q":
                        needExit = true;
                        break;
                    case "setm":
                        Console.Write("input m: ");
                        m = Console.ReadLine().Trim();
                        break;
                    case "do":
                        Console.Write("input password: ");
                        var pass = Console.ReadLine().Trim();
                        Console.WriteLine(EncryptPass(pass));
                        break;
                    case "do3":
                        Console.Write("input password: ");
                        var pass2 = Console.ReadLine().Trim();
                        Console.WriteLine(EncryptPassV3(pass2));
                        break;
                    case "verity":
                    case "v":
                        Console.Write("input password: ");
                        var pass3= Console.ReadLine().Trim();
                        if (m.Trim() == string.Empty)
                        {
                            Console.Write("input m: ");
                            m = Console.ReadLine().Trim();
                        }
                        if (VerityPass(pass3, m))
                        {
                            Console.WriteLine("Success,");
                        }
                        else
                        {
                            Console.WriteLine("Fail,");
                        }
                        break;
                    case "test":
                        Test();
                        break;
                }

            } while (!needExit);
            Console.WriteLine("Bye-");
        }

        internal static void Test()
        {
            var passEncrypt = "0x02008B0FC4A11F0E4F48B3984C289269C556E19C86D2EE219166A30435129FA1C493CB189A36592AEC356074AFCA318E914DB0E1432BBA84ADE56E1D8320CA4B1E124B767322";
            var pass = "123456";

            if (VerityPass(pass, passEncrypt))
            {
                Console.WriteLine("Test OK!");
            }
        }

        internal static bool VerityPass(string pass, string passEncrypt)
        {
            var reader = new BinReader(passEncrypt);
            var writer = new BinWriter();

            switch (reader.ReadHexString(2))
            {
                case "0300":
                    writer.WriteUnicodeText(pass);
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    var verity_val3 = reader.ReadHexString(64);
                    var sha3_512_prog = new SHA3_512();
                    var rlt3 = sha3_512_prog.Make(writer.ToArray());

                    if (rlt3.ToUpper() == verity_val3.ToUpper())
                    {
                        return true;
                    }
                    break;
                case "0200":
                    writer.WriteUnicodeText(pass);
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    var verity_val = reader.ReadHexString(64);
                    var sha512_prog = new SHA512();
                    var rlt = sha512_prog.Make(writer.ToArray());

                    if (rlt.ToUpper() == verity_val.ToUpper())
                    {
                        return true;
                    }
                    break;
                case "0100":
                    writer.WriteUnicodeText(pass);
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    writer.Write(reader.ReadByte());
                    var verity_val2 = reader.ReadHexString(40);
                    var sha1_prog = new SHA1();
                    var rlt2 = sha1_prog.Make(writer.ToArray());

                    if (rlt2.ToUpper() == verity_val2.Substring(0, rlt2.Length).ToUpper())
                    {
                        return true;
                    }
                    break;
            }

            return false;
        }
        internal static string EncryptPass(string pass)
        {
            var salt = Guid.NewGuid().ToByteArray();
            return EncryptPass(pass, new byte[4] { salt[2], salt[4], salt[1], salt[7] });
        }
        internal static string EncryptPass(string pass, byte[] salt)
        {
            var rlt = string.Empty;
            var writer = new BinWriter();

            writer.WriteUnicodeText(pass);
            writer.Write(salt[0]);
            writer.Write(salt[1]);
            writer.Write(salt[2]);
            writer.Write(salt[3]);

            var sha = new SHA512();
            rlt += "0x0200";
            rlt += salt[0].ToString("X2");
            rlt += salt[1].ToString("X2");
            rlt += salt[2].ToString("X2");
            rlt += salt[3].ToString("X2");
            rlt += sha.Make(writer.ToArray()).ToUpper();

            return rlt;
        }
        internal static string EncryptPassV3(string pass)
        {
            var salt = Guid.NewGuid().ToByteArray();
            return EncryptPassV3(pass, new byte[4] { salt[2], salt[4], salt[1], salt[7] });
        }
        internal static string EncryptPassV3(string pass, byte[] salt)
        {
            var rlt = string.Empty;
            var writer = new BinWriter();

            writer.WriteUnicodeText(pass);
            writer.Write(salt[0]);
            writer.Write(salt[1]);
            writer.Write(salt[2]);
            writer.Write(salt[3]);

            var sha = new SHA3_512();
            rlt += "0x0300";
            rlt += salt[0].ToString("X2");
            rlt += salt[1].ToString("X2");
            rlt += salt[2].ToString("X2");
            rlt += salt[3].ToString("X2");
            rlt += sha.Make(writer.ToArray()).ToUpper();

            return rlt;
        }
    }
}